#include "netComponents.h"
#include "tools/cJSON.h"
#include <QtDebug>

static bool gNewInitStatus = false;

// 全局初始化网络模块函数
bool TcpGlobalInit()
{
    // 已初始化过网络模块的，直接返回
    if(true == gNewInitStatus)
    {
        return gNewInitStatus;
    }

#ifdef Q_OS_UNIX
    // Linux编译环境，无需执行该操作
    gNewInitStatus = true;
#else
    // Windows编译环境
    WORD wVersionRequested;
    WSADATA wsaData;

    do
    {
        gNewInitStatus = false;
        
        //WinSock初始化
        wVersionRequested = MAKEWORD(2, 2);
        int err = WSAStartup(wVersionRequested,&wsaData);
        if(0 != err)
        {
            qDebug() <<"[TcpGlobalInit] WSAStartup failed with error: " << err;
            break;
        }

        //确认WinSock DLL支持版本2.2
        if(2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion))
        {
            qDebug() <<"[TcpGlobalInit] Could not find a usable version of Winsock.dll";
            WSACleanup();   //释放为该程序分配的资源，终止对winsock动态库的使用
            break;
        }
        else
        {
            qDebug() <<"[TcpGlobalInit] The Winsock 2.2 dll was found okay";
        }

        gNewInitStatus = true;
    }while(0);
#endif

    return gNewInitStatus;
}

NodeProcCallback::NodeProcCallback()
{
    m_bCallBackStatus = false;
    m_bCallBackExit = false;
    m_listMsgInfos.clear();
}

// 设置数据是否回调上层
void NodeProcCallback::setCallBackStatus(const bool bCallBack)
{ 
    m_bCallBackStatus = bCallBack;
}

// 调用层获取数据
void NodeProcCallback::getCallBackMsgWithCondition(std::list<MSG_INFO> &listMsgInfo)
{
    std::unique_lock<std::mutex> lck (m_mtxCallBackMsg);
    m_conCallBack.wait_for(lck, std::chrono::milliseconds(NODECALLBACK_WAITTIME_MS), [&](){return (!m_listMsgInfos.empty() || m_bCallBackExit);});
    if(false == m_bCallBackExit && !m_listMsgInfos.empty())
    {
        m_listMsgInfos.swap(listMsgInfo);
    }
}

// 上层中止调用
void NodeProcCallback::setCallBackExit()
{
    std::unique_lock<std::mutex> lck (m_mtxCallBackMsg);
    m_bCallBackExit = true;
    m_conCallBack.notify_all();
}

// 获取已有消息
int getRecvMsg(const int iMaxSize, std::list<MSG_INFO> &listMsg)
{
    listMsg.clear();
    if(0 == iMaxSize)
    {
        return 0;
    }

    return 0;
}

// 接收数据，并设置超时时间
int MyDataRecv(const SOCKET hSocket, char *pBuf, const int nLen, const int timeout)
{
    if (nLen <= 0)
    {
        return nLen;
    }

    int nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(int));
    if (0 != nRet)
    {
        qDebug() <<"[MyDataRecv] setsockopt faild" << nRet;
        return nRet;
    }

    int nRead = recv(hSocket, pBuf, nLen, 0);
    if(nRead <= 0)
    {
        nRead = 0;
    }

    return nRead;
}

// 发送数据，并设置超时时间
int MyDataSend(const SOCKET hSocket, const char *pBuf, const unsigned int nLen, const int timeout)
{
    int nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(int));
    if (0 != nRet)
    {
        qDebug() <<"[MyDataSend] setsockopt faild" << nRet;
        return 0;
    }

    int   nLeft = nLen;
    char* ptr = (char*)pBuf;
    int   nWritten;
    while(nLeft > 0)
    {
        nWritten = send(hSocket, ptr, nLeft, 0);
        if(-1 == nWritten)
        {
            qDebug() << "[MyDataSend] data send faild, break ->" << errno;
            break;
        }

        nLeft -= nWritten;
        ptr   += nWritten;
    }

    return (nLen - nLeft);
}

// 生成消息发送报文
bool createSendMsg(const std::list<MSG_INFO> &listMsg, std::string &strSendMsg)
{
    bool bRet = false;
    cJSON *pRoot = nullptr;
    char *pRet = nullptr;

    do
    {
        strSendMsg.clear();

        pRoot = cJSON_CreateArray();
        if(nullptr == pRoot)
        {
            qDebug() << "[createSendMsg] cJSON_CreateArray faild";
            break;
        }

        for(auto& it : listMsg)
        {
            cJSON *pObj = cJSON_CreateObject();
            if(nullptr == pObj)
            {
                qDebug() << "[createSendMsg] cJSON_CreateObject faild, continue";
                continue;
            }
            cJSON_AddStringToObject(pObj, NET_DES_NODEID, it.strID.c_str());
            cJSON_AddStringToObject(pObj, NET_DES_NODETIME, it.strTime.c_str());
            cJSON_AddStringToObject(pObj, NET_DES_NODEMSG, it.strMsg.c_str());
            cJSON_AddNumberToObject(pObj, NET_DES_NODETYPE, it.nType);
            cJSON_AddItemToArray(pRoot, pObj);
        }

        // 打印结果报文
        pRet = cJSON_PrintUnformatted(pRoot);
        if(nullptr == pRet)
        {
            qDebug() << "[createSendMsg] cJSON_PrintUnformatted faild";
            break;
        }

        // 返回组装的报文
        strSendMsg.assign(pRet);

        bRet = true;
    }while(0);

    if(nullptr != pRoot)
    {
        cJSON_Delete(pRoot);
        pRoot = nullptr;
    }

    if(nullptr != pRet)
    {
        free(pRet);
        pRet = nullptr;
    }

    return bRet;
}

// 解析消息接收报文
bool parseRecvMsg(const std::string &strRecvMsg, std::list<MSG_INFO> &listMsg)
{
    bool bRet = false;
    cJSON *pRoot = nullptr;
    listMsg.clear();
    do
    {
        if(strRecvMsg.empty())
        {
            break;
        }

        pRoot = cJSON_Parse(strRecvMsg.c_str());
        if(nullptr == pRoot)
        {
            break;
        }

        unsigned int iCnt = cJSON_GetArraySize(pRoot);
        for(unsigned int idx = 0; idx < iCnt; idx++)
        {
            cJSON* pObj = cJSON_GetArrayItem(pRoot, idx);
            if(nullptr == pObj)
            {
                continue;
            }

            cJSON* pNodeID = cJSON_GetObjectItem(pObj, NET_DES_NODEID);
            cJSON* pNodeTime = cJSON_GetObjectItem(pObj, NET_DES_NODETIME);
            cJSON* pNodeMsg = cJSON_GetObjectItem(pObj, NET_DES_NODEMSG);
            cJSON* pNodeType = cJSON_GetObjectItem(pObj, NET_DES_NODETYPE);
            if(nullptr == pNodeID || nullptr == pNodeTime || nullptr == pNodeMsg || nullptr == pNodeType)
            {
                continue;
            }

            MSG_INFO stMsg;
            stMsg.nType = (MSG_INFO_TYPE)pNodeType->valueint;
            stMsg.strID.assign(pNodeID->valuestring);
            stMsg.strTime.assign(pNodeTime->valuestring);
            stMsg.strMsg.assign(pNodeMsg->valuestring);
            listMsg.push_back(stMsg);
        }

        bRet = true;
    } while (0);
    
    if(nullptr != pRoot)
    {
        cJSON_Delete(pRoot);
        pRoot = nullptr;
    }

    return bRet;
}

// 消息格式化打印（html格式）
void getBrowserShowInfo(const MSG_INFO& stMsgInfo, QString &strInfo, QString &strShowMsg)
{
    QString strTitle;
    QString strMsgData;
    switch (stMsgInfo.nType)
    {
    case MSG_INFO_TYPE_MSGDATA:
        {
            strTitle = QString::fromStdString(stMsgInfo.strID);
            strMsgData = QString::fromStdString(stMsgInfo.strMsg);
        }
        break;
    case MSG_INFO_TYPE_STATUS_NEW:
        {
            strTitle = QString("系统消息");
            strMsgData = QString("%1 节点已上线").arg(QString::fromStdString(stMsgInfo.strID));          
            break;
        }
    case MSG_INFO_TYPE_STATUS_OFF:
        {
            strTitle = QString("系统消息");
            strMsgData = QString("%1 节点已掉线").arg(QString::fromStdString(stMsgInfo.strID));
            break;
        }
    case MSG_INFO_TYPE_STATUS_EXIT:
        {
            strTitle = QString("系统消息");
            strMsgData = QString("%1 节点已退出").arg(QString::fromStdString(stMsgInfo.strID));
            break;
        }
    default:
        break;
    }

    strInfo = QString("<table><tr>"
                        "<td style=\"vertical-align: middle; font-size:13px; color:#0000FF\">%1 &nbsp;</td>"
                        "<td style=\"vertical-align: middle; font-size:13px; color:#007500; font-weight:bold;\">%2 </td>"
                        "</tr></table>").arg(QString::fromStdString(stMsgInfo.strTime), strTitle);
    strShowMsg = QString("<table><tr>"
                        "<td style=\"vertical-align: middle; font-size:16px; color:#FF2D2D;\"> &nbsp; %1</td>"
                        "</tr></table>").arg(strMsgData);
}